/*
 * $Id: Object.m,v 1.15 2006-06-18 10:20:46 bacon Exp $
 */

#include <xpo/bas/Object.h>
#include <xpo/bas/Protocol.h>
#include <xp/bas/memory.h>
#include <xp/bas/assert.h>

/* TODO: remove the 2 files below */
#include <xp/bas/stdio.h>
#include <xp/bas/stdlib.h>

static inline struct objc_object* __alloc (struct objc_class* class)
{
	xp_size_t size;
	struct objc_object* obj;

	size = xp_sizeof(struct objc_object) + class->instance_size;
	/*obj = (struct objc_object*)xp_calloc(1, size);*/
	obj = (struct objc_object*)objc_calloc(1, size);
	if (obj == XP_NULL) return nil;

#if defined(__APPLE__) || defined(__MACOSX__)
	obj->isa = class;
#else
	obj->class_pointer = class;
#endif
	return obj;
}

@implementation XpObject

+ (id) alloc
{
	/*return __alloc (self);*/
	return class_create_instance (self);
}

+ (id) new
{
	id obj = [self alloc];
	if (obj == nil) return nil;
	return [obj init];
}

- (id) init
{
	return self;
}

- (void) dealloc
{
	/*if (self != nil) xp_free (self);*/
	/*if (self != nil) objc_free (self);*/
	if (self != nil) object_dispose (self);
}

- (id) copy
{
	return object_copy (self);
}

- (Class) class
{
	return object_get_class (self);
}

- (Class) superclass
{
	return object_get_super_class (self);
}

- (MetaClass) metaclass
{
	return object_get_meta_class (self);
}

- (const char*) className
{
	/*if (object_is_class(self))*/ return object_get_class_name(self);
	/*return object_get_class_name(object_get_class(self));*/
}

- (BOOL) isClass
{
	return object_is_class (self);
}

- (BOOL) isInstance
{
	return object_is_instance (self);
}

- (BOOL) isKindOf: (Class) class_object
{
	Class c;

	for (c = self->isa; c != nil; c = class_get_super_class(c))
	{
		if (c == class_object) return YES;
	}

	return NO;
}

+ (BOOL) canUnderstand: (SEL) selector
{
	return class_get_class_method (self, selector) != METHOD_NULL;
}

- (BOOL) respondsTo: (SEL) selector
{
	if (object_is_instance(self))
		return class_get_instance_method (self->isa, selector) != METHOD_NULL;
	else
		return class_get_class_method (self->isa, selector) != METHOD_NULL;
}

- (BOOL) conformsTo: (Protocol*)protocol
{
	struct objc_protocol_list* p;
	xp_size_t i;

	p = ((struct objc_class*)self)->class_pointer->protocols;
	while (p != XP_NULL) 
	{
		for (i = 0; i < p->count; i++) 
		{
			if ([p->list[i] conformsTo: protocol]) return YES;
		}	
		p = p->next;
	}

	if ([self superclass] != nil) 
		return [[self superclass] conformsTo : protocol];

	return NO;
}

- (id) perform: (SEL) selector
{
	IMP msg = objc_msg_lookup (self, selector);
	xp_assert (msg != XP_NULL);
	return (*msg) (self, selector);
}

- (id) perform: (SEL) selector with: arg1
{
	IMP msg = objc_msg_lookup (self, selector);
	xp_assert (msg != XP_NULL);
	return (*msg) (self, selector, arg1);
}

- (id) perform: (SEL) selector with: arg1 with: arg2
{
	IMP msg = objc_msg_lookup (self, selector);
	xp_assert (msg != XP_NULL);
	return (*msg) (self, selector, arg1, arg2);
}

#if defined(__APPLE__) || defined(__MACOSX__)
- (id) forward: (SEL)sel: (marg_list)args
{
	return self;
}
#endif

- (void) subclassResponsibility
{
	xp_printf (XP_TEXT("subclass responsibility"));
	xp_exit (1);	
}

@end
